package com.evil.application.strategy.reporting;

import cn.hutool.core.collection.CollectionUtil;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregate;
import com.alibaba.fastjson.JSON;
import com.evil.application.enums.reporting.ReportingTypeEnum;
import com.evil.application.pojo.dto.reporting.AggBaseDTO;
import com.evil.application.pojo.dto.reporting.ApplicationReportingDTO;
import com.evil.application.pojo.dto.reporting.ReportingTargetDTO;
import com.evil.application.pojo.dto.reporting.data.ReportingDataRespDTO;
import com.evil.application.pojo.dto.reporting.data.ReportingDataSeriesDTO;
import com.evil.application.pojo.dto.reporting.data.ReportingDataSeriesValuesDTO;
import com.evil.common.core.util.StreamUtil;
import com.evil.common.es.dto.AggTreeParam;
import com.evil.common.es.dto.AggTreeResult;
import com.evil.common.es.enums.DimensionEnum;
import com.evil.common.es.util.ElasticsearchUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;

/**
 * @author liyang
 * @date 2025-02-12 14:06
 */
@Slf4j
@Service
@AllArgsConstructor
public abstract class ReportingDataChartAbstract implements ReportingData {

    public abstract ReportingTypeEnum type();

    @Override
    public ReportingDataRespDTO calculation(ApplicationReportingDTO reportingDTO, Aggregate aggregations) {
        ReportingDataRespDTO reportingDataRespDTO = new ReportingDataRespDTO(reportingDTO.getReportingKey());
        if (null == aggregations) {
            return reportingDataRespDTO;
        }
        // 聚合树信息
        AggTreeParam<AggBaseDTO> param = this.analysisAggTreeParam(reportingDTO);

        // aggTree
        List<AggTreeResult> aggTree = ElasticsearchUtil.analysis(null, param, aggregations);
        log.info("reportData|chart|key:{}|aggTree:{}", reportingDTO.getReportingKey(), JSON.toJSONString(aggTree));

        if (CollectionUtil.isEmpty(aggTree)) {
            return reportingDataRespDTO;
        }

        // 构建聚合分析
        AnalysisSeries analysis = new AnalysisSeries(param);
        // 首次分析聚合树
        this.analysisAggTree(aggTree, analysis);
        // 分析计算
        this.analysisCal(aggTree, analysis);

        // 根据 aggTree 与 聚合树信息 生成eChart数据
        reportingDataRespDTO.setReportingSeries(analysis.reportingSeries());

        return reportingDataRespDTO;
    }

    private void analysisCal(List<AggTreeResult> aggTree, AnalysisSeries analysisSeries) {
        if (CollectionUtil.isEmpty(aggTree) || analysisSeries.getRowKeyMap().isEmpty()) {
            return;
        }
        for (AggTreeResult first : aggTree) {
            switch (first.getDimensionEnum()) {
                case ROW -> {
                    String rowName = String.valueOf(first.getValue());

                    AggKey rowKeyMap = analysisSeries.getRowKeyMap();
                    // 行维度-补全
                    rowKeyMap.getNextKey(first.getTitle()).ifPresent(title -> {
                        LinkedHashSet<String> allKeys = rowKeyMap.get(title);
                        // 现有key
                        Map<String, AggTreeResult> keyMap = StreamUtil.toMapK(first.getChildren(), e -> String.valueOf(e.getValue()));
                        // 补全子级
                        first.completion(allKeys, DimensionEnum.ROW, title, keyMap);
                    });

                    // 递归
                    this.analysisCal(first.getChildren(), analysisSeries);
                    // 到指标了
                    if (null != analysisSeries.value) {
                        analysisSeries.value.setRowName(rowName);
                        analysisSeries.seriesValues.add(analysisSeries.value);

                        // 还原
                        analysisSeries.value = null;
                    }
                    // 没到指标
                    else if (CollectionUtil.isNotEmpty(analysisSeries.seriesValues)) {
                        ReportingDataSeriesDTO series = new ReportingDataSeriesDTO(rowName);
                        series.setSeriesValues(analysisSeries.seriesValues);
                        analysisSeries.seriesList.add(series);

                        // 还原
                        analysisSeries.seriesValues = new ArrayList<>();
                    }
                }
                case TARGET -> {
                    AggBaseDTO aggBaseDTO = analysisSeries.getParam().getTargetMap().get(first.getTitle());
                    if (aggBaseDTO instanceof ReportingTargetDTO target) {
                        ReportingDataSeriesValuesDTO value = new ReportingDataSeriesValuesDTO();
                        value.setRowName(null);
                        value.setValue(first.getValue());
                        value.setDisplayValue(target.format(first.getValue()));
                        analysisSeries.value = value;
                    }
                }
            }
        }
    }

    private static class AnalysisSeries extends Analysis {

        private final List<ReportingDataSeriesDTO> seriesList;

        private List<ReportingDataSeriesValuesDTO> seriesValues;

        private ReportingDataSeriesValuesDTO value;

        public AnalysisSeries(AggTreeParam<AggBaseDTO> param) {
            super(param);
            this.seriesList = new ArrayList<>();
            this.seriesValues = new ArrayList<>();
        }

        public List<ReportingDataSeriesDTO> reportingSeries() {
            // 未分类
            if (CollectionUtil.isEmpty(this.seriesList) && CollectionUtil.isNotEmpty(this.seriesValues)) {
                ReportingDataSeriesDTO series = new ReportingDataSeriesDTO("未分类");
                series.setSeriesValues(this.seriesValues);
                this.seriesList.add(series);
            }
            return seriesList;
        }
    }
}
